package parser;

import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;

import udes.ds.agent.AbstractEquation;
import udes.ds.agent.BasicEquation;
import udes.ds.agent.MultiplicativeEquation;
import udes.ds.agent.SummativeEquation;

public class EquationParser {
	final static String operator_multp = "*";
	final static String operator_add = "+";
	final static String operator_sous = "-";
	final static String operator_div = "/";
	final static String parenth_ovr = "(";
	final static String parenth_fer = ")";

	public String infixeToPostFixe(String equation_In) {

		char[] infixArray = equation_In.toCharArray();
		int infixArrayLenght = infixArray.length;

		Stack<Character> pile = new Stack<Character>();
		String result = "";
		Hashtable<Character, Integer> priorite = new Hashtable<Character, Integer>();
		priorite.put('^', 4);
		priorite.put('(', 3);
		priorite.put(')', 3);
		priorite.put('/', 2);
		priorite.put('*', 2);
		priorite.put('+', 1);
		priorite.put('-', 1);

		char temp = ' ';
		for (int i = 0; i < infixArrayLenght; i++) {

			// si operateur
			if (infixArray[i] == '+' || infixArray[i] == '-'
					|| infixArray[i] == '*' || infixArray[i] == '/'
					|| infixArray[i] == '^') {

				while (!pile.isEmpty() && pile.peek() != '(') {
					if (priorite.get(infixArray[i]) <= priorite
							.get(pile.peek())) {
						temp = pile.pop();
						result += temp + " ";
					} else
						break;
				}
				pile.push(infixArray[i]);

				// si parentese ouvrante
			} else if (infixArray[i] == '(') {

				pile.push(infixArray[i]);

				// si parentese fermante
			} else if (infixArray[i] == ')') {
				while (!pile.isEmpty() && pile.peek() != '(') {
					temp = pile.pop();
					result += temp;
				}

				if (!pile.isEmpty()) {
					pile.pop();
				}
				// si un chiffre ou une lettre
			} else // if((infixArray[i] >= '0') && (infixArray[i] <= '9'))
			{
				while ((i < infixArrayLenght)
						&& validateCharacter(infixArray[i])) {
					result = result + infixArray[i++];
				}
				result += " ";
				i--;
			}
		}

		// depiler le resultat
		while (!pile.isEmpty()) {
			temp = pile.pop();
			result += temp;
		}

		return result;
	}

	// cette methode permet d'evaluer une expression posteFixe
	public static void evaluatePostFixeExepression(
			Vector<AbstractEquation> out, String expression)
			throws ParserException {

		// Evaluation of expression PostFixe

		String temp = "";
		AbstractEquation operand1 = null;
		AbstractEquation operand2 = null;
		AbstractEquation equation;
		expression = expression.trim();
		char[] postFixeArray = (expression.trim()).toCharArray();
		Stack<AbstractEquation> pile = new Stack<AbstractEquation>();
		int postFixArrayLenght = postFixeArray.length;

		for (int i = 0; i < postFixArrayLenght; i++) {

			if (validateCharacter(postFixeArray[i])) {
				while ((i < postFixArrayLenght)
						&& (validateCharacter(postFixeArray[i]))) {
					temp += postFixeArray[i++];
				}
				try {
					pile.push(new BasicEquation(Integer.parseInt(temp), 0));
				} catch (Exception e) {
					pile.push(new BasicEquation(1, 1));
				}

				temp = "";
				i--;
			} else if (postFixeArray[i] == '+' || postFixeArray[i] == '-'
					|| postFixeArray[i] == '*' || postFixeArray[i] == '/'
					|| postFixeArray[i] == '^') {

				operand1 = pile.pop();
				operand2 = pile.pop();
				if (postFixeArray[i] == '+') {
					equation = new SummativeEquation(operand1, operand2);
					pile.push(equation);
				} else if (postFixeArray[i] == '*') {
					equation = new MultiplicativeEquation(operand1, operand2);
					pile.push(equation);
				} else if (postFixeArray[i] == '^') {
					equation = new BasicEquation(1,
							(int) ((BasicEquation) operand1).getCoefficient());
					pile.push(equation);
				}
			} else {
				// throw new ParserException();
			}
		}
		// add the element to the vector
		out.add(pile.pop());
	}

	// validate if the character is number ou lettre
	private static boolean validateCharacter(char c) {
		boolean isvalide = false;

		isvalide = (c > '0' && c < '9') || (c == 'x') || (c == 'X');

		return isvalide;
	}

	public static void validateExpression(String str) throws ParserException {
		for (char c : str.toCharArray()) {
			if (!(validateCharacter(c) || c == '+' || c == '-' || c == '*'
					|| c == '(' || c == ')' || c == '^')) {
				throw new ParserException(c);
			}
		}
	}

}
